-- grytole@gmail.com 21-Jul-2012

TILESIZE = 48

function initmap()
  map = {}
  spacepos = 1
  for i = 1, 16 do
    map[i] = i
  end
  math.randomseed( os.time() )
  for i = 1, 100 do
    a = math.random( 1, 16 )
    b = math.random( 1, 16 )
    map[a], map[b] = map[b], map[a]
  end
  for i = 1, 16 do
    if map[i] == 16 then spacepos = i end
  end
  return map, spacepos
end

function inittiles()
  tiles = {}
  for i = 1, 15 do
    isok, tile = sdl.fill( {w = TILESIZE, h = TILESIZE}, {r = 181, g = 230, b = 29} )
    if isok == false then
      print( 'Fill failed:', tile )
      sdl.quit()
      os.exit()
    end
    tiles[i] = tile
    isok, text = sdl.text( i, {font = './examples/fifteen/ubuntu.ttf', size = 14},
                           {r = 0, g = 0, b = 0} )
    if isok == false then
      print( 'Text rendering failed:', text )
      sdl.quit()
      os.exit()
    end
    isok, errmsg = sdl.blit( text, nil, tiles[i], {x = 5, y = 5} )
    if isok == false then
      print( 'Blit failed:', errmsg )
      sdl.quit()
      os.exit()
    end
  end
  isok, space = sdl.fill( {w = TILESIZE, h = TILESIZE}, {r = 0, g = 0, b = 0} )
  if isok == false then
    print( 'Fill failed:', space )
    sdl.quit()
    os.exit()
  end
  tiles[16] = space
  return tiles
end

function drawfield( map, tiles )
  for i = 1, 16 do
    xpos = (TILESIZE + 2) * ((i - 1) % 4) + 1
    ypos = (TILESIZE + 2) * (math.ceil( (i / 4) ) - 1) + 1
    isok, errmsg = sdl.blit( tiles[ map[i] ], nil, nil, {x = xpos, y = ypos} )
    if isok == false then
      print( 'Blit failed:', errmsg )
      sdl.quit()
      os.exit()
    end
  end
  sdl.flip()
end

function issolved( map )
  for i = 1, 15 do
    if map[i] ~= i then
      return false
    end
  end
  return true
end

function showscore()
  isok, popup = sdl.fill( {w = 150, h = 50}, {r = 128, g = 0, b = 0} )
  if isok == false then
    print( 'Fill failed:', popup )
    sdl.quit()
    os.exit()
  end
  isok, text = sdl.text( 'Puzzle solved', {font = './examples/fifteen/ubuntu.ttf', size = 20},
                         {r = 255, g = 255, b = 255} )
  if isok == false then
    print( 'Text rendering failed:', text )
    sdl.quit()
    os.exit()
  end
  isok, errmsg = sdl.blit( text, nil, popup, {x = 12, y = 12} )
  if isok == false then
    print( 'Blit failed:', errmsg )
    sdl.quit()
    os.exit()
  end
  isok, errmsg = sdl.blit( popup, nil, nil, {x = 25, y = 75} )
  if isok == false then
    print( 'Blit failed:', errmsg )
    sdl.quit()
    os.exit()
  end
  sdl.flip()
end

isok, errmsg = sdl.init( {w = 200, h = 200, bpp = 32}, 'Game of Fifteen' )
if isok == false then
  print( 'Init failed:', errmsg )
  os.exit()
end

map, spacepos = initmap()
tiles = inittiles()

drawfield( map, tiles )

repeat
  isok, events = sdl.events()
  if isok == false then
    print( 'Getting events failed:', events )
    sdl.quit()
    os.exit()
  else
    for k, v in ipairs( events ) do
      if v.type == 'quit' then done = true end
      if v.type == 'keydown' then
        if v.key == 'escape' then done = true end
        if v.key == 'up' then
          swappos = spacepos - 4
          if swappos >= 1 then
            map[spacepos], map[swappos] = map[swappos], map[spacepos]
            spacepos = swappos
          end
        end
        if v.key == 'down' then
          swappos = spacepos + 4
          if swappos <= 16 then
            map[spacepos], map[swappos] = map[swappos], map[spacepos]
            spacepos = swappos
          end
        end
        if v.key == 'right' then
          if spacepos % 4 ~= 0 then
            swappos = spacepos + 1
            map[spacepos], map[swappos] = map[swappos], map[spacepos]
            spacepos = swappos
          end
        end
        if v.key == 'left' then
          if spacepos % 4 ~= 1 then
            swappos = spacepos - 1
            map[spacepos], map[swappos] = map[swappos], map[spacepos]
            spacepos = swappos
          end
        end
        drawfield( map, tiles )
        if issolved( map ) then
          showscore()
          sdl.delay( 3000 )
          done = true
        end
      end
    end
  end
  sdl.delay( 10 )
until done == true

sdl.quit()

-- eof
